package com.ksyun.campus.metaserver.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ksyun.campus.metaserver.domain.MetaServerInfo;
import com.ksyun.campus.metaserver.domain.dto.ApiResponse;
import com.ksyun.campus.metaserver.zk.ZooKeeperService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Set;

/**
 * Interceptor to ensure write operations are only handled by the leader
 */
@Slf4j
@Component
public class LeaderAwareInterceptor implements HandlerInterceptor {
    
    @Autowired
    private ZooKeeperService zooKeeperService;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    // Write operations that require leader
    private static final Set<String> WRITE_OPERATIONS = Set.of(
            "/api/v1/meta/mkdirs",
            "/api/v1/meta/createFile", 
            "/api/v1/meta/delete",
            "/api/v1/meta/allocateBlocks",
            "/api/v1/meta/commit",
            "/api/v1/admin/fsck/run"
    );
    
    // Methods that are write operations
    private static final Set<String> WRITE_METHODS = Set.of("POST", "PUT", "DELETE");
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        String method = request.getMethod();
        
        // Check if this is a write operation
        boolean isWriteOperation = isWriteOperation(requestURI, method);
        
        if (isWriteOperation && !zooKeeperService.isLeader()) {
            log.debug("Rejecting write operation {} {} - not leader", method, requestURI);
            
            // Get current leader info
            String leaderAddress = getLeaderAddress();
            
            // Return NOT_LEADER response
            ApiResponse<?> errorResponse = ApiResponse.notLeader(leaderAddress);
            
            response.setStatus(HttpServletResponse.SC_CONFLICT); // 409
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
            response.getWriter().flush();
            
            return false;
        }
        
        return true;
    }
    
    private boolean isWriteOperation(String requestURI, String method) {
        // Check specific write operation paths
        if (WRITE_OPERATIONS.contains(requestURI)) {
            return true;
        }
        
        // Check if method is a write method for API paths
        if (WRITE_METHODS.contains(method) && requestURI.startsWith("/api/v1/")) {
            return true;
        }
        
        return false;
    }
    
    private String getLeaderAddress() {
        try {
            MetaServerInfo leaderInfo = zooKeeperService.getLeaderInfo();
            if (leaderInfo != null) {
                return leaderInfo.getHost() + ":" + leaderInfo.getPort();
            }
        } catch (Exception e) {
            log.warn("Failed to get leader info", e);
        }
        return "unknown";
    }
}
